package com.xhai.common.utils.encrypt;

import com.xhai.common.exception.ServiceException;
import com.xhai.common.utils.classes.ByteArrayUtils;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;

/**
 * @author xhai
 * @description 解密工具
 * @date 2025/5/31
 */
public class DecryptUtils {
    // 算法常量
    private static final String ALGORITHM = "RSA";
    private static final String RSA_TRANSFORMATION_256 = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding";

    private static final int DATA_SIZE = 256;

    // AES密钥长度（16/24/32字节对应AES-128/192/256）
    private static final int AES_KEY_SIZE = 32; // AES-256
    // 加密算法/模式/填充方式
    private static final String AES_TRANSFORMATION_CBC = "AES/CBC/PKCS5Padding";

    public static PrivateKey getRSAPrivateKeyFromBase64(String base64PrivateKey) throws GeneralSecurityException {
        try {
            // 尝试标准 Base64 解码
            byte[] encodedKey = Base64.getDecoder().decode(base64PrivateKey);
            return generatePrivateKeyFromPKCS8(encodedKey);
        } catch (IllegalArgumentException e) {
            // 尝试 URL 安全的 Base64 解码
            byte[] encodedKey = Base64.getUrlDecoder().decode(base64PrivateKey);
            return generatePrivateKeyFromPKCS8(encodedKey);
        }
    }

    private static PrivateKey generatePrivateKeyFromPKCS8(byte[] encodedKey) throws GeneralSecurityException {
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey);
        return keyFactory.generatePrivate(keySpec);
    }

    /**
     * 根据私钥解密数据
     *
     * @param privateKey
     * @param encryptedData
     * @return
     * @throws Exception
     */
    public static String decryptRSA(PrivateKey privateKey, String encryptedData) throws Exception {
        // 检查密钥长度是否足够（至少 2048 位）
        int keyLength = privateKey.getEncoded().length * 8;
        if (keyLength < 2048 && RSA_TRANSFORMATION_256.contains("OAEP")) {
            throw new ServiceException("RSA 密钥长度不足，需要至少 2048 位才能使用 OAEP 填充");
        }

        Cipher cipher = Cipher.getInstance(RSA_TRANSFORMATION_256);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        // 解密
        byte[] encryptedDataBytes = Base64.getDecoder().decode(encryptedData);
        byte[] decryptedDataBytes = cipher.doFinal(encryptedDataBytes);

        return new String(decryptedDataBytes, StandardCharsets.UTF_8);
    }

    /**
     * 验证密钥长度是否符合AES要求
     */
    private static void validateAESKeyLength(String key) throws IllegalArgumentException {
        if (key == null || key.getBytes(StandardCharsets.UTF_8).length != AES_KEY_SIZE) {
            throw new IllegalArgumentException("AES密钥必须为" + (AES_KEY_SIZE * 8) + "位");
        }
    }

    /**
     * AES-CBC解密方法
     *
     * @param encryptedData 格式为 "Base64(IV).Base64(Ciphertext)"
     * @param secretKey     密钥（长度必须为16/24/32字节）
     * @return 解密后的明文
     * @throws Exception 包含密钥长度错误、解密失败等异常
     */
    public static String decryptAES(String encryptedData, String secretKey) throws Exception {
        try {
            // 验证密钥长度
            validateAESKeyLength(secretKey);

            // 分割IV和密文
            String[] parts = encryptedData.split(":", 2);
            if (parts.length != 2) {
                throw new IllegalArgumentException("加密数据格式错误，需包含IV和密文");
            }

            // 解码IV和密文
            byte[] ivBytes = Base64.getDecoder().decode(parts[0]);
            byte[] cipherBytes = Base64.getDecoder().decode(parts[1]);

            // 转换密钥
            SecretKeySpec keySpec = new SecretKeySpec(
                    secretKey.getBytes(StandardCharsets.UTF_8), "AES");

            // 初始化Cipher
            Cipher cipher = Cipher.getInstance(AES_TRANSFORMATION_CBC);
            cipher.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(ivBytes));

            // 执行解密
            byte[] decryptedBytes = cipher.doFinal(cipherBytes);
            return new String(decryptedBytes, StandardCharsets.UTF_8);
        } catch (IllegalArgumentException e) {
            // 密钥长度错误或数据格式错误
            throw e;
        } catch (Exception e) {
            // 其他解密异常（如填充错误、无效密钥等）
            throw new Exception("AES解密失败: " + e.getMessage(), e);
        }
    }
}
